#include "Cats/CatStates/CatState.h"
#include "Cats/CatStates/CatState_Base_Obstacle.h"
#include "Cats/BaseCat.h"
#include "Cats/CatSpriteLoader.h"
#include "Map/GameMap.h"
#include "Supporting/Enums/EnumCatAnimation.h"

CatState_Base_Obstacle::CatState_Base_Obstacle(BaseCat* pCatRef):CatState(pCatRef)
{
	_stopTimer = 0;
	_hitObstacle = false;
	_isJumpingUp = true;
	_exitState = false;
}

CatState_Base_Obstacle::~CatState_Base_Obstacle()
{

}

void CatState_Base_Obstacle::runOnEnter()
{
	//do not exit state yet
	_exitState = false;

	//decide whether to hit obstacle or not
	_hitObstacle = hitObstacleDecision();

	//setup variables for hitting/not hitting obstacle
	if (_hitObstacle)
	{
		//setup timer for slow duration
		_stopTimer = _pCatRef->getSlowDuration();
		//reduce cat's speed
		_pCatRef->setSpeedMultiplier(_pCatRef->getSpeedMultiplier() / _pCatRef->getSlowSpeedMultiplier());
	}
	else
	{
		//start jumping upwards
		_isJumpingUp = true;
		//record current y position
		_floorY = _pCatRef->getPositionY();
	}

}

void CatState_Base_Obstacle::onResume()
{
	CatState::onResume();
	_pCatRef->stopAllActions();
	_pCatRef->runAction(CatSpriteLoader::getCatAnimation(_pCatRef->getCatType(), CAT_ANIM_WALK));
}


void CatState_Base_Obstacle::update(float timeDiff)
{
	if (!_exitState) //guard against on pause/resume re-run of this block
	{
		if (_hitObstacle)
			_exitState = hitObstacleUpdate(timeDiff);
		else
			_exitState = avoidObstacleUpdate(timeDiff);
	}

	if (_exitState)
		_pCatRef->setNextCatState(CAT_CHASE);
}

void CatState_Base_Obstacle::onExit()
{
	CatState::onExit();
	_exitState = false;
	if (_hitObstacle)
		_pCatRef->setSpeedMultiplier(_pCatRef->getSpeedMultiplier() * _pCatRef->getSlowSpeedMultiplier());
}


bool CatState_Base_Obstacle::hitObstacleDecision()
{
	int randomChance = arc4random() % 100;
	//if randomed chance is less than actual chance
	return randomChance < _pCatRef->getObstacleHitChance();
}

bool CatState_Base_Obstacle::hasHitObstacle()
{
	return _pGameMapRef->checkCollisionWithObstacles(_pCatRef->getRect(), _pCatRef->getPosition());
}

bool CatState_Base_Obstacle::hitObstacleUpdate(float timeDiff)
{
	//count down the timer
	_stopTimer -= timeDiff;

	//return to chase state when timer ends
	if (_stopTimer <= 0)
	{
		return true;
	}

	//move the cat
	_pCatRef->move(timeDiff);

	return false;
}

bool CatState_Base_Obstacle::avoidObstacleUpdate(float timeDiff)
{
	//move to the left while jumping
	_pCatRef->move(timeDiff);

	//move up/down
	if (_isJumpingUp)
	{
		//jump upwards
		_pCatRef->setPositionY(_pCatRef->getPositionY() + (_pCatRef->getBaseJumpSpeed() * timeDiff) * _pCatRef->getSpeedMultiplier());

		//if reached the peaked of the jump
		if (_pCatRef->getPositionY() >= _floorY + _pCatRef->getBaseJumpHeight())
		{
			_isJumpingUp = false;
			_pCatRef->setPositionY(_floorY + _pCatRef->getBaseJumpHeight());
		}
	}
	else
	{
		//drop downwards
		_pCatRef->setPositionY(_pCatRef->getPositionY() - (_pCatRef->getBaseJumpSpeed() * timeDiff) * _pCatRef->getSpeedMultiplier());

		//if reached the floor
		if (_pCatRef->getPositionY() <= _floorY)
		{
			//reset values for next jump
			_pCatRef->setPositionY(_floorY);

			//check if still colliding with obstacles
			if (hasHitObstacle())
				//continue jumping
				_isJumpingUp = true;
			else
				//exit state
				return true;
		}

		return false;
	}
}
